/*  File    : vgen.c
 *  Abstract:
 */

#define S_FUNCTION_NAME vgen
#define S_FUNCTION_LEVEL 2

#include "simstruc.h"

#define RD      mxGetPr(ssGetSFcnParam(S, 0))[0]
#define RT      mxGetPr(ssGetSFcnParam(S, 1))[0]
#define ED      mxGetPr(ssGetSFcnParam(S, 2))[0]
#define ET      mxGetPr(ssGetSFcnParam(S, 3))[0]

#define sa   *uPtrs[0]
#define sb   *uPtrs[1]
#define sc   *uPtrs[2]
#define ia   *uPtrs[3]
#define ib   *uPtrs[4]
#define ic   *uPtrs[5]
#define Udc  *uPtrs[6]

#define van      y[0]
#define vbn      y[1]
#define vcn      y[2]

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *    The sizes information is used by Simulink to determine the S-function
 *    block's characteristics (number of inputs, outputs, states, etc.).
 */
static void mdlInitializeSizes(SimStruct *S) {
    ssSetNumSFcnParams(S, 4);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        return; /* Parameter mismatch will be reported by Simulink */
    }
    
    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);
    
    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, 7);
    ssSetInputPortDirectFeedThrough(S, 0, 1);
    
    if (!ssSetNumOutputPorts(S, 1)) return;
    ssSetOutputPortWidth(S, 0, 3);
    
    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);
    ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
    
    if (ssGetSimMode(S) == SS_SIMMODE_RTWGEN && !ssIsVariableStepSolver(S)) {
        ssSetErrorStatus(S, "S-function vsfunc.c cannot be used with RTW "
                "and Fixed-Step Solvers because it contains variable"
                " sample time");
    }
    
    /* Take care when specifying exception free code - see sfuntmpl_doc.c */
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}

/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    Variable-Step S-function
 */
static void mdlInitializeSampleTimes(SimStruct *S) {
    ssSetSampleTime(S, 0, 0.0);
    ssSetOffsetTime(S, 0, 0.0);
    ssSetModelReferenceSampleTimeDefaultInheritance(S);
}

#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
 * Abstract:
 */
static void mdlInitializeConditions(SimStruct *S) {
}

/* Function: mdlOutputs =======================================================
 * Abstract:
 */
static void mdlOutputs(SimStruct *S, int_T tid) {
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0);
    real_T *y = ssGetOutputPortSignal(S, 0);
    
    //Phase a
    if (sa > 0) {
        if (ia >= 0.0)
            //Upper transistor conducts
            y[0]=Udc/2.0-ET-RT*ia;
        else
            //Upper diode conducts
            y[0]=Udc/2.0+ED-RD*ia;
    }
    else {
        if (ia >= 0.0)
            //Lower diode conducts
            y[0]=-Udc/2.0-ED-RD*ia;
        else
            //Lower transistor conducts
            y[0]=-Udc/2.0+ET-RT*ia;
    }
    
    //Phase b
    if (sb > 0) {
        if (ib >= 0.0)
            //Upper transistor conducts
            y[1]=Udc/2.0-ET-RT*ib;
        else
            //Upper diode conducts
            y[1]=Udc/2.0+ED-RD*ib;
    }
    else {
        if (ib >= 0.0)
            //Lower diode conducts
            y[1]=-Udc/2.0-ED-RD*ib;
        else
            //Lower transistor conducts
            y[1]=-Udc/2.0+ET-RT*ib;
    }
    
    //Phase c
    if (sc > 0) {
        if (ic >= 0.0)
            //Upper transistor conducts
            y[2]=Udc/2.0-ET-RT*ic;
        else
            //Upper diode conducts
            y[2]=Udc/2.0+ED-RD*ic;
    }
    else {
        if (ic >= 0.0)
            //Lower diode conducts
            y[2]=-Udc/2.0-ED-RD*ic;
        else
            //Lower transistor conducts
            y[2]=-Udc/2.0+ET-RT*ic;
    }
    
    //Output
    //y[0]=(sa*Udc)/2.0;
    //y[1]=(sb*Udc)/2.0;
    //y[2]=(sc*Udc)/2.0;
}

#define MDL_UPDATE
/* Function: mdlUpdate ========================================================
 * Abstract:
 *    This function is called once for every major integration time step.
 *    Discrete states are typically updated here, but this function is useful
 *    for performing any tasks that should only take place once per integration
 *    step.
 */
static void mdlUpdate(SimStruct *S, int_T tid) {
}

/* Function: mdlTerminate =====================================================
 * Abstract:
 *    No termination needed, but we are required to have this routine.
 */
static void mdlTerminate(SimStruct *S) {
}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif